<template>
	<view class="motor-app">
		<!-- 标题 -->
		<view class="inibox">
			<view class="inibox_in">
				<view class="inibox_tt_a" hover-class="inibox_ttacv" @click="tobelFn" v-if="lanname == ''">点击连接设备
				</view>
				<view class="inibox_tt_b" hover-class="inibox_ttacv" @click="lampRFn" v-if="lanname != ''">点击断开设备
				</view>
			</view>
			<view :class="['lights-box', lightsOn ? 'lights-on' : 'lights-off']" @click="iniIFFn">
				{{ lightsOn ? '设备已初始化' : '设备未初始化' }}
			</view>
		</view>
		<!-- 圈数显示 -->
		<view class="counter">
			<view class="value">{{ numberOfCircles}}</view>
			<view class="label">圈</view>
		</view>

		<!-- 状态灯 -->
		<view class="status">
			<view class="dot" :class="statusClass"></view>
			<view class="text">{{ statusText }}</view>
		</view>

		<!-- 电机结构 -->
		<view class="motor-wrapper">
			<view class="motor-shell">
				<view class="stator left-stator"></view>
				<view class="stator right-stator"></view>
				<view class="brush brush-left"></view>
				<view class="brush brush-right"></view>
				<view class="rotor" :class="rotorClass">
					<view class="shaft"></view>
					<view class="coil coil-1"></view>
					<view class="coil coil-2"></view>
					<view class="commutator"></view>
				</view>
			</view>
		</view>
		<!-- 切换转速 -->
		<view class="rotatzhuns">
			<view class="rotatzhflax">
				<view class="">
					<uni-data-checkbox v-model="rotatvalue" selectedColor="#383d41" :localdata="rotatdata"
						mode="tag"></uni-data-checkbox>
				</view>
			</view>
			<view class="zhunsbtn" @click="switchMode">
				点击切换转速
			</view>
		</view>

		<!-- 控制按钮 -->
		<view class="buttons">
			<view class="btn forward" :class="{ disabled: isForwardDisabled }"
				@click="!isForwardDisabled && start('forward')">
				<view class="icon">▶</view>
				<view class="labeltext">
					<view>正</view>
					<view>转</view>
				</view>
			</view>

			<view class="btn pause" :class="{ disabled: isPauseDisabled }" @click="pauseMotor">
				<view class="icon">⏸</view>
				<view class="labeltext">
					<view>暂</view>
					<view>停</view>
				</view>
			</view>

			<view class="btn reverse" :class="{ disabled: isReverseDisabled }"
				@click="!isReverseDisabled && start('reverse')">
				<view class="icon">◀</view>
				<view class="labeltext">
					<view>反</view>
					<view>转</view>
				</view>
			</view>
		</view>
		<!-- 初始化电机 -->
		<u-modal :show="infIF" title="初始化设备" @confirm="cinfconfirmIF" @cancel="infcancelIF" showCancelButton></u-modal>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				status: 'stopped',
				direction: 'forward',
				alertDialog: false,
				titlename: '',
				fontSize: '20px',
				yyNubAc: 0, //脉冲数
				infIF: false, //初始化
				deviceId: '', //蓝牙
				serviceId: '', //蓝牙
				characteristicId: '', //蓝牙
				fff: '', //蓝牙
				lanname: '', //蓝牙
				showSlot: '暂停',
				timerTmei: null, //定时器
				rotatvalue: 1200, //转速
				rotatdata: [{
					text: '600转',
					value: 600
				}, {
					text: '1200转',
					value: 1200
				}, {
					text: '1800转',
					value: 1800
				}, {
					text: '2400转',
					value: 2400
				}],
				modeSwitching: null, //模式切换
				rotationalSpeedUP: ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0x00', '0x00', '0x00', '0xC8',
					'0x00', '0x64', '0x00', '0x64', '0x69', '0x83'
				], //转速正转
				rotationalSpeedDN: ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0xFF', '0xFF', '0xFF', '0x38',
					'0x00', '0x64', '0x00', '0x64', '0x7D', '0x92'
				], //转速倒转
				numberOfCircles: 0, //圈数
				lightsOn: false, //灯光
			};
		},
		computed: {
			statusText() {
				if (this.status === 'paused') return '电机已暂停';
				if (this.status === 'running') return this.direction === 'forward' ? '正转中' : '反转中';
				return '电机已停止';
			},
			statusClass() {
				return {
					forward: this.status === 'running' && this.direction === 'forward',
					reverse: this.status === 'running' && this.direction === 'reverse',
					paused: this.status === 'paused',
				};
			},
			rotorClass() {
				return {
					spinning: this.status === 'running',
					reverse: this.direction === 'reverse'
				};
			},
			isForwardDisabled() {
				return this.status === 'running' && this.direction === 'forward';
			},
			isReverseDisabled() {
				return this.status === 'running' && this.direction === 'reverse';
			},
			isPauseDisabled() {
				return this.status !== 'running';
			}
		},
		beforeDestroy() {
			clearInterval(this.timerTmei)
			this.pauseMotor()
			console.log('销毁');
		},
		onShow() {
			// 保持屏幕常亮
			uni.setKeepScreenOn({
				keepScreenOn: true
			});
			uni.showLoading({
				mask: true,
				title: '连接设备中...'
			});
			setTimeout(() => {
				uni.hideLoading()
			}, 3000)
			//蓝牙服务
			this.getBLEDeviceServices()
			// 断开设备
			uni.onBLEConnectionStateChange((res) => {
				// 该方法回调中可以用于处理连接意外断开等异常情况
				if (res.connected !== true) {
					console.log('意外断开');
					this.lanname = ''
					uni.$u.vuex('vuex_devicename', '')
					uni.$u.vuex('vuex_deviceId', '')
				}
			})
			this.lanname = this.vuex_devicename
			this.deviceId = this.vuex_deviceId
		},
		methods: {
			// 电机行走距离
			motorTravelingDistance(data) {
				console.log('电机行走圈数', data);
				if (data * 1 > 4294967.295 / 2) {
					let nub = (4294967.295 - data * 1).toFixed(0)
					this.numberOfCircles = (nub * -1).toFixed(0)
				} else {
					this.numberOfCircles = (data * 1).toFixed(0)
				}
			},
			// 开始
			start(dir) {
				this.direction = dir;
				this.status = 'running';
				console.log('dir', dir);
				// 正转
				if (dir == 'forward') {
					this.forwordFn()
				}
				// 反转
				if (dir == 'reverse') {
					this.reversalFn()
				}
				clearInterval(this.timerTmei)
				setTimeout(() => {
					this.timerTmei = setInterval(() => {
						this.aLLBrakeFnxx()
					}, 300)
				}, 500)

			},
			// 暂停
			pauseMotor() {
				clearInterval(this.timerTmei)
				this.status = 'paused';
				this.riseDevFnTHxx()
			},
			// 纵向按钮正转
			forwordFn() {
				console.log('上');
				this.modeSwitching = 1
				// 点位参数
				let hposData = this.rotationalSpeedUP
				let initiate = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x0F', '0xD6', '0x1A']
				this.conbuffer(hposData)
				setTimeout(() => {
					this.conbuffer(initiate)
				}, 300)

			},
			// 纵向按钮反转 转速 rotationalSpeed
			reversalFn() {
				console.log('下');
				this.modeSwitching = 2
				let hposData = this.rotationalSpeedDN
				let initiate = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x0F', '0xD6', '0x1A']
				this.conbuffer(hposData)
				setTimeout(() => {
					this.conbuffer(initiate)
				}, 300)
			},
			// 松开暂停
			riseDevFnTHxx() {
				this.modeSwitching = null
				console.log('松开暂停');
				let pause = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x07', '0xD7', '0xDC']
				this.conbuffer(pause)
				setTimeout(() => {
					this.conbuffer(pause)
				}, 300)
				setTimeout(() => {
					this.conbuffer(pause)
				}, 600)
			},
			// 询问地址脉冲圈数
			aLLBrakeFnxx() {
				let brakea = ['0x01', '0x03', '0x60', '0x41', '0x00', '0x06', '0x8B', '0xDC']
				this.conbuffer(brakea)
			},
			// 初始化
			iniIFFn() {
				this.infIF = true
			},

			// 初始化电机确定
			cinfconfirmIF() {
				this.iniFn()
				this.infIF = false
			},
			// 初始化电机取消
			infcancelIF() {
				this.infIF = false
			},
			// 脉冲清零归零模式
			iniFn() {
				clearInterval(this.timerTmei)
				uni.showToast({
					title: '正在初始化...',
					icon: 'loading',
					mask: true,
					duration: 4000
				});
				// 驱动器上电初始化
				let ini = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x01', '0x57', '0xDE']
				// 驱动器正常运行，但电机未使能，松开刹车
				let brakeDel = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x03', '0xD6', '0x1F']
				// 电机给电，处于可运行状态
				let electric = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x0F', '0xD6', '0x1A']
				// 设置回零模式 01 06 60 60 00 06 17 D6
				let hpos = ['0x01', '0x06', '0x60', '0x60', '0x00', '0x06', '0x17', '0xD6']
				// 设定回零方式 01 10 60 7C 00 08 10 00 00 03 E8 00 01 00 00 00 64 03 E8 00 00 00 64
				let hposTop = ['0x01', '0x10', '0x60', '0x7C', '0x00', '0x08', '0x10', '0x00', '0x00', '0x03', '0xE8',
					'0x00', '0x00', '0x00', '0x00', '0x00', '0x64', '0x03', '0xE8', '0x00', '0x00', '0x00', '0x64',
					'0x0D', '0xBE'
				]
				// 开始归零
				let startToZero = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x1F', '0xD7', '0xD6']
				this.conbuffer(ini)
				setTimeout(() => {
					this.conbuffer(brakeDel)
				}, 300)
				setTimeout(() => {
					this.conbuffer(electric)
				}, 600)
				setTimeout(() => {
					this.conbuffer(hpos)
				}, 900)
				setTimeout(() => {
					this.conbuffer(hposTop)
				}, 1200)
				setTimeout(() => {
					this.conbuffer(startToZero)
					setTimeout(() => {
						this.verticalZeroingYY()
					}, 300)
				}, 1500)
			},
			// 横向初始化
			verticalZeroingYY() {
				// 驱动器上电初始化
				let ini = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x01', '0x57', '0xDE']
				// 驱动器正常运行，但电机未使能，松开刹车 
				let brakeDel = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x03', '0xD6', '0x1F']
				// 电机给电，处于可运行状态
				let electric = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x0F', '0xD6', '0x1A']
				// 暂停电机运行
				let hposTop = ['0x01', '0x06', '0x60', '0x40', '0x01', '0x0F', '0xD7', '0x8A']
				// 设置速度模式
				let hpos = ['0x01', '0x06', '0x60', '0x60', '0x00', '0x03', '0xD7', '0xD5']

				this.conbuffer(ini)
				setTimeout(() => {
					this.conbuffer(brakeDel)
				}, 300)
				setTimeout(() => {
					this.conbuffer(electric)
				}, 600)
				setTimeout(() => {
					this.conbuffer(hposTop)
				}, 900)
				setTimeout(() => {
					this.conbuffer(hpos)
				}, 1200)
				setTimeout(() => {
					this.aLLBrakeFnxx()
				}, 1500)
				setTimeout(() => {
					this.switchMode()
					// 暂停电机
					setTimeout(() => {
						this.riseDevFnTHxx()
					}, 2000)
				}, 2000)
			},
			// 切换模式
			switchMode() {
				uni.showToast({
					title: '切换模式中...',
					icon: 'loading',
					mask: true,
					duration: 2000
				});
				console.log('切换模式', this.rotatvalue);
				let initiate = ['0x01', '0x06', '0x60', '0x40', '0x00', '0x0F', '0xD6', '0x1A']
				// 设置位置模式
				// let inib = ['0x01', '0x06', '0x60', '0x60', '0x00', '0x01', '0x56', '0x14']
				if (this.rotatvalue == 600) {
					// 设置点位参数 600转速
					this.rotationalSpeedUP = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0x00', '0x00',
						'0x00',
						'0x64', '0x00', '0x64', '0x00', '0x64', '0xF9', '0x9B'
					]
					// 倒转
					this.rotationalSpeedDN = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0xFF', '0xFF',
						'0xFF', '0x9C',
						'0x00', '0x64', '0x00', '0x64', '0x0C', '0x4B'
					]
				}
				if (this.rotatvalue == 1200) {
					// 设置点位参数 1200转速
					this.rotationalSpeedUP = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0x00', '0x00',
						'0x00',
						'0xC8', '0x00', '0x64', '0x00', '0x64', '0x69', '0x83'
					]
					// 倒转
					this.rotationalSpeedDN = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0xFF', '0xFF',
						'0xFF', '0x38',
						'0x00', '0x64', '0x00', '0x64', '0x7D', '0x92'
					]
				}
				if (this.rotatvalue == 1800) {
					// 设置点位参数 1200转速
					this.rotationalSpeedUP = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0x00', '0x00',
						'0x01',
						'0x2C', '0x00', '0x64', '0x00', '0x64', '0x18', '0x44'
					]
					// 倒转
					this.rotationalSpeedDN = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0xFF', '0xFF',
						'0xFE', '0xD4',
						'0x00', '0x64', '0x00', '0x64', '0xED', '0x94'
					]
				}
				if (this.rotatvalue == 2400) {
					// 设置点位参数 1200转速
					this.rotationalSpeedUP = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0x00', '0x00',
						'0x01',
						'0x90', '0x00', '0x64', '0x00', '0x64', '0x49', '0x9F'
					]
					// 倒转
					this.rotationalSpeedDN = ['0x01', '0x10', '0x60', '0x81', '0x00', '0x04', '0x08', '0xFF', '0xFF',
						'0xFE', '0x70',
						'0x00', '0x64', '0x00', '0x64', '0x9C', '0x4D'
					]
				}
				// 电机运行上
				if (this.modeSwitching == 1) {
					setTimeout(() => {
						this.forwordFn()
					}, 1000)
				}
				// 电机运行下
				if (this.modeSwitching == 2) {
					setTimeout(() => {
						this.reversalFn()
					}, 1000)
				}
			},
			//监听消息变化++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
			listenValueChange(data) {
				setTimeout(() => {
					uni.onBLECharacteristicValueChange(res => {
						if (this.lanname != '') {
							let resHex = this.ab2hex(res.value)
							this.monitoringInformationProcessing(resHex)
						} else {
							this.monitoringInformationProcessing(res)
						}
					})
				}, 300)
			},
			monitoringInformationProcessing(res) {
				let resHex = res
				console.log('监听数据', resHex, resHex.length);
				//电机状态
				if (resHex.length == 34) {
					// 电机初始化状态
					// 初始化
					this.lightsOn = true
					// 获取脉冲
					let str = resHex.substr(14, 8)
					// 脉冲圈数
					console.log('脉冲', this.hexToDecimal(str) / 1000);
					// 电机距离
					this.motorTravelingDistance((this.hexToDecimal(str) / 1000).toFixed(1))

				}
			},
			// 输入蓝牙数据
			conbuffer(data) {
				let msg = data
				console.log('发送数据格式蓝牙', data);
				// 向蓝牙设备发送一个0x00的16进制数据
				const buffer = new ArrayBuffer(msg.length)
				const dataView = new DataView(buffer)
				// dataView.setUint8(0, 0)
				for (var i = 0; i < msg.length; i++) {
					// dataView.setUint8(i, msg.charAt(i).charCodeAt())
					dataView.setUint8(i, msg[i]);
				}
				this.sendMsgToKey(buffer)
			},
			/* 向设备发送消息(分包发送，单包20字节，递归发送)
			 */
			// ArrayBuffer转16进度字符串示例
			ab2hex(buffer) {
				const hexArr = Array.prototype.map.call(
					new Uint8Array(buffer),
					function(bit) {
						return ('00' + bit.toString(16)).slice(-2)
					}
				)
				return hexArr.join('')
			},
			sendMsgToKey(buffer) {
				var that = this //vue中的this
				const packageSize = 20 //分包大小
				if (buffer.byteLength <= 20) { //如果小于20直接发送，不再继续调用
					uni.writeBLECharacteristicValue({
						// 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
						deviceId: that.deviceId,
						// 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
						serviceId: that.serviceId,
						// 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
						// characteristicId: that.fff, //第二步写入的特征值
						characteristicId: that.fff, //第二步写入的特征值
						// 这里的value是ArrayBuffer类型
						value: buffer,
						writeType: 'write',
						success: (res) => {
							//此时设备已接收到你写入的数据
							console.log('写入11111');

						},
						fail: (err) => {
							console.log('传输失败', err)
							this.status = 'paused';
							clearInterval(this.timerTmei)
							this.lanname = this.vuex_devicename
						},
						complete: function() {}
					})
				} else { //如果大于20发送完成后继续递归调用
					var newData = buffer.slice(20)
					var writeBuffer = buffer.slice(0, 20)
					uni.writeBLECharacteristicValue({
						// 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
						deviceId: that.deviceId,
						// 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
						serviceId: that.serviceId,
						// 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
						characteristicId: that.fff, //第二步写入的特征值
						// 这里的value是ArrayBuffer类型
						value: writeBuffer,
						writeType: 'write',
						success: function(res) {
							console.log('写入22222');
							//写入后继续递归调用发送剩下的数据
							setTimeout(() => {
								that.sendMsgToKey(newData)
							}, 100)
						},
						fail: (err) => {
							console.log('传输失败', err)
							clearInterval(this.timerTmei)
							this.status = 'paused';
							this.lanname = this.vuex_devicename
						},
						complete: function() {}
					})
				}
			},
			// 启用 notify 功能
			notifyBLECharacteristicValueChange(characteristicId) {
				console.log('启用 notify 功能');
				uni.notifyBLECharacteristicValueChange({
					state: true, // 启用 notify 功能
					// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
					deviceId: this.deviceId,

					// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
					serviceId: this.serviceId,
					// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
					characteristicId: this.characteristicId,
					success: (res) => {
						console.log('蓝牙名字', res);
						// vuex
						// uni.$u.vuex('vuex_devicename', this.vuexlist.name)
						uni.hideLoading()
						this.listenValueChange()
						uni.showToast({
							title: '设备已连接',
							mask: true,
							duration: 1000
						});
						this.iniFn()
						console.log('蓝牙服务已开启');
					},
					fail: (res) => {
						uni.hideLoading()
						uni.showToast({
							title: '连接设备失败',
							icon: 'fail',
							mask: true,
							duration: 1000
						});

					}
				})
			},

			//获取蓝牙的所有服务
			getBLEDeviceServices() {
				setTimeout(() => {
					uni.getBLEDeviceServices({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId: this.vuex_deviceId,
						success: (res) => {
							console.log('获取vuex_deviceId', this.vuex_deviceId);
							console.log('获取蓝牙所有服务', res);
							//E95D93AF-251D-470A-A062-FA1922DFA9A8
							//6E400001-B5A3-F393-E0A9-E50E24DCCA9E
							res.services.forEach((item) => {

								if (item.uuid.indexOf("0000FFF0") != -1) {
									this.serviceId = item.uuid;
									//获取特征
									this.getBLEDeviceCharacteristics()
								}
								if (item.uuid.indexOf("0000FFE0") != -1) {
									this.serviceId = item.uuid;
									//获取特征
									this.getBLEDeviceCharacteristics()
								}
								if (item.uuid.indexOf("00001000") != -1) {
									this.serviceId = item.uuid;
									//获取特征
									this.getBLEDeviceCharacteristics()
								}
							})
						}
					})
				}, 1000)
			},
			//获取蓝牙特征
			getBLEDeviceCharacteristics() {
				console.log('获取蓝牙特征值', this.deviceId, this.serviceId, );
				setTimeout(() => {
					uni.getBLEDeviceCharacteristics({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId: this.deviceId,
						// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
						serviceId: this.serviceId,
						success: (res) => {

							this.characteristics = res.characteristics
							res.characteristics.forEach((item) => {

								if (item.uuid.indexOf("FFF2") != -1) {
									this.fff = item.uuid
								}
								if (item.uuid.indexOf("FFE1") != -1) {
									this.fff = item.uuid
								}
								if (item.uuid.indexOf("0000FFE1") != -1) {
									this.characteristicId = item.uuid
									//利用传参的形势传给下面的notify，这里的uuid如果都需要用到，就不用做判断了，建议使用setTimeout进行间隔性的调用此方法
									this.notifyBLECharacteristicValueChange(item.uuid)
								}
								if (item.uuid.indexOf("0000FFF1") != -1) {
									this.characteristicId = item.uuid
									this.notifyBLECharacteristicValueChange(item.uuid)
								}
								// EW-DTU02
								if (item.uuid.indexOf("00001001") != -1) {
									this.fff = item.uuid
								}
								if (item.uuid.indexOf("00001002") != -1) {
									this.characteristicId = item.uuid
									this.notifyBLECharacteristicValueChange(item.uuid)
								}
							})
						},
						fail: (res) => {
							console.log(res)
						}
					})
				}, 1000)
			},
			// 修改数组里面指定对象
			updateItemById(array, id, newData) {
				return array.map(item => {
					if (item.id === id) {
						return {
							...item,
							...newData
						};
					}
					return item;
				});
			},
			// 删除指定字符串最后面
			removeTrailingSubstring(str, suffix) {
				if (!str || !suffix) return str;

				const strLength = str.length;
				const suffixLength = suffix.length;

				// 检查字符串是否以指定的子串结尾
				if (strLength >= suffixLength &&
					str.substring(strLength - suffixLength) === suffix) {
					return str.substring(0, strLength - suffixLength);
				}

				return str;
			},
			// 16进制转2进制
			hexToBinaryW(hexString) {
				if (!/^[0-9A-Fa-f]+$/.test(hexString)) {
					throw new Error("Invalid hexadecimal string");
				}
				const decimal = parseInt(hexString, 16);
				return decimal.toString(2);
			},
			// 10进制转32位二进制补码
			NumberOf1(num) {
				// 获取负数的绝对值
				const absoluteValue = Math.abs(num);

				// 将绝对值转换为32位二进制字符串
				let binaryString = absoluteValue.toString(2);

				// 确保二进制字符串长度为32位
				while (binaryString.length < 32) {
					binaryString = '0' + binaryString;
				}

				// 对二进制字符串取反
				const invertedBinaryString = binaryString.split('').map(bit => bit === '0' ? '1' : '0').join('');

				// 将取反后的二进制字符串转换为数字并加1
				const twosComplement = parseInt(invertedBinaryString, 2) + 1;

				// 再次将补码转换为32位二进制字符串
				binaryString = twosComplement.toString(2);
				// 确保二进制字符串长度为32位
				while (binaryString.length < 32) {
					binaryString = '0' + binaryString;
				}

				return binaryString;
			},
			// 二进制补码转16进制
			binaryToHex(binaryStr) {
				// 确保二进制字符串是32位
				if (binaryStr.length !== 32) {
					throw new Error('Binary string must be 32 bits long');
				}

				// 将二进制字符串转换为数字
				var number = parseInt(binaryStr, 2);

				// 转换为16进制并返回结果
				return number.toString(16);
				// 示例使用
				// var binaryStr = '010101010101010101010101010101010'; // 32位二进制补码
				// var hexStr = binaryToHex(binaryStr);
			},
			//数组求平均
			averageSum(arr) {
				if (arr.length === 0) {
					return 0; // 当数组为空时，平均值为0
				}

				let sum = 0;
				for (let i = 0; i < arr.length; i++) {
					sum += arr[i];
				}

				return sum / arr.length;
			},
			// 长度不够补0
			strRepair(str, nub) {
				let nubm = nub * 1
				let strif = str + ''
				if (strif.length < nubm) {
					for (let i = 0; i < nubm - str.length; i++) {
						strif = '0' + strif
					}
				}
				return strif
			},
			//给每个数组添加0x
			ocstr(data) {
				let arr = []
				for (let i = 0; i < data.length; i++) {
					data[i] = '0x' + data[i]
				}
				return data
			},
			// 每2个字符串为一个元素数组
			chunkStringByTwo(str) {
				const result = [];
				for (let i = 0; i < str.length; i += 2) {
					result.push(str.slice(i, i + 2));
				}
				return result;
			},
			// 处理ASCLL 30 -00
			ascllFn(data) {
				let str = data + ''
				let arr = this.chunkStringByTwo(str)

				for (let i = 0; i < arr.length; i++) {
					if (arr[i] == '00') {
						arr[i] = '30'
					}
				}
				let arrnew = arr

				let strnre = ''
				for (let i = 0; i < arrnew.length; i++) {
					strnre += arrnew[i]
				}
				return strnre
			},
			// CRC16校验
			crc16(dataHexString) {
				const dataBytes = [];
				for (let i = 0; i < dataHexString.length; i += 2) {
					dataBytes.push(parseInt(dataHexString.substr(i, 2), 16));
				}

				let crc = 0xFFFF;
				const polynomial = 0xA001;

				for (const byte of dataBytes) {
					crc ^= byte;
					for (let i = 0; i < 8; i++) {
						if (crc & 0x0001) {
							crc = ((crc >> 1) ^ polynomial) & 0xFFFF;
						} else {
							crc >>= 1;
						}
					}
				}
				let crcstr = crc.toString(16).toUpperCase();
				if (crcstr.length % 2 == 0) {
					let result = crcstr.match(/.{1,2}/g)
					return result;
				} else {
					let str = '0' + crcstr
					let result = str.match(/.{1,2}/g)
					return result;
				}
			},
			// 16进制转10进制
			hexToDecimal(hex) {
				return parseInt(hex, 16);
			},
			// 10进制转16进制
			decimalToHex(data) {
				let decimal = data * 1
				let hex = decimal.toString(16).toUpperCase();
				3
				if (hex.length % 2 !== 0) {
					return '0' + hex
				} else {
					return hex
				}
				// return decimal.toString(16).toUpperCase();
			},
			// 16进制转字符串 ASCII码
			hexToString(hex) {
				let str = '';
				for (let i = 0; i < hex.length; i += 2) {
					let charCode = parseInt(hex.substr(i, 2), 16);
					str += String.fromCharCode(charCode);
				}
				return str;
			},

			//字符串转16进制
			stringToHex(data) {
				let str = data + ''
				return str.split('').map(function(char) {
					return char.charCodeAt(0).toString(16).padStart(2, '0');
				}).join('');
			},
			// 16进制转汉字
			hexToChinese(hex) {
				var str = '';
				for (var i = 0; i < hex.length / 4; i++) {
					var codePoint = parseInt(hex.substr(i * 4, 4), 16); // 获取每四位的十六进制值并转换成十进制
					str += String.fromCharCode(codePoint); // 根据Unicode编码生成对应的字符
				}
				return str;
			},
			// 汉字转16进制
			convertToHex(str) {
				let result = '';
				for (let i = 0; i < str.length; i++) {
					result += str.charCodeAt(i).toString(16);
				}
				return result;
			},
			// 随机数
			getRandomNumber(min, max) {
				return Math.floor(Math.random() * (max - min + 1)) + min;
			},
			// 蓝牙
			tobelFn() {
				//在起始页面跳转到test.vue页面并传递参数
				uni.navigateTo({
					url: '/pages/index/devBEL'
				});

			},
			//断开连接
			lampRFn() {
				uni.closeBLEConnection({
					deviceId: this.vuex_deviceId,
					success: (res) => {
						uni.showToast({
							title: '设备已断开',
							icon: 'success',
							mask: true,
							duration: 1000
						});
						this.lanname = ''
						uni.$u.vuex('vuex_devicename', '')
					}
				})
			},
		},
	};
</script>
<style scoped lang="scss">
	/* 🌌 页面布局 */
	.motor-app {
		padding: 20rpx;
		background: #121212; // $color-bg
		color: #f0f0f0; // $color-text
		font-family: Arial, sans-serif;
		text-align: center;
	}

	/* 🏷️ 标题 */
	.inibox {
		margin: 0rpx 0 30rpx 0;
		display: flex;
		align-items: center;
		justify-content: space-between;

		.lights-box {
			width: 330rpx;
			text-align: center;
			font-size: 30rpx;
			padding: 20rpx 0;
			border-radius: 200rpx;
		}

		.lights-off {
			color: #7b7d78; // $color-text 的暗灰色
			background-color: #e3e5db;
		}

		.lights-on {
			color: #ffffff;
			background-color: #766793;
		}

		.inibox_in {
			width: 330rpx;

			.inibox_tt_a {
				text-align: center;
				color: #bd241a;
				font-size: 30rpx;
				padding: 20rpx 0;
				border-radius: 200rpx;
				background-color: #eee4e2;
			}

			.inibox_tt_b {
				text-align: center;
				color: #ffffff;
				font-size: 30rpx;
				padding: 20rpx 0;
				border-radius: 200rpx;
				background-color: #00b457;
			}

			.inibox_ttacv {
				color: #ffffff;
				background-color: #d0d4d4;
			}
		}

		.inibox_acv {
			color: #ffffff;
			background-color: #d0d4d4;
		}
	}

	/* 切换转速 */
	.rotatzhuns {
		padding: 10rpx;
		margin: 20rpx 0;
		border-radius: 10rpx;
		background-color: rgba(195, 226, 235, 0.1);
		// border: 1rpx solid rgba(195, 226, 235, 0.2);

		.rotatzhflax {
			display: flex;
			align-items: center;
			justify-content: center;
		}

		.zhunsbtn {
			width: 100%;
			font-size: 40rpx;
			padding: 10rpx 0rpx;
			margin: 10rpx 0;
			background: linear-gradient(135deg, #3a3f44, #3a3f44);
			// border: 1rpx solid rgba(195, 226, 235, 0.3);
			border-radius: 8rpx;
			display: flex;
			justify-content: center;
			align-items: center;
			transition: all 0.2s;
			cursor: pointer;
			font-weight: 500;
			color: rgba(195, 226, 235, 0.8);

			&:active {
				background-color: #c3e2eb;
				opacity: 0.6;
				transform: scale(0.8);
			}
		}
	}

	/* 🔢 圈数 */
	.counter {
		padding: 20rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		border-radius: 10rpx;
		margin-bottom: 30rpx;
		color: #aaffff;
		// border: 3rpx solid rgba(51, 51, 51, 0.9);
		// background-color: rgba(51, 51, 51, 0.8);
		background: #1c1c1c;
		border: 3rpx solid #2e2e2e;
		/* 内阴影和外阴影营造立体感 */
		box-shadow:
			inset 0 0 20rpx #444444,
			0 0 10rpx rgba(0, 0, 0, 0.9);
		font-family: 'qingyuan';

		.value {
			width: 500rpx;
			padding: 5rpx 0;
			margin-right: 20rpx;
			// background-color: #000000;
			font-size: 90rpx;
			border-radius: 10rpx;
		}

		.label {
			color: #00ff7f;
			font-size: 60rpx;
		}
	}

	/* 🟡 状态灯 */
	.status {
		display: flex;
		align-items: center;
		justify-content: center;

		.dot {
			width: 24rpx;
			height: 24rpx;
			border-radius: 50%;
			margin-right: 15rpx;
			background: #444444;
			/* 默认暗色，停止状态 */

			&.forward {
				background: #3dff67;
				/* $color-forward */
				animation: breathe 2s ease-in-out infinite;
			}

			&.reverse {
				background: #fff703;
				/* $color-reverse */
				animation: breathe 2s ease-in-out infinite;
			}

			&.paused {
				background: #ff5640;
				/* $color-pause */
				animation: breathe 2s ease-in-out infinite;
			}
		}

		.text {
			font-size: 40rpx;
		}
	}

	/* ⚙️ 电机图 */
	/* 伺服电机外壳 */
	.motor-wrapper {
		/* 电机整体容器，居中对齐 */
		padding: 30rpx 0;
		display: flex;
		justify-content: center;
		align-items: center;

		.motor-shell {
			/* 电机外壳，圆形，带金属质感的边框和阴影 */
			width: 400rpx;
			height: 400rpx;
			border-radius: 50%;
			background: #1c1c1c;
			border: 18rpx solid #2e2e2e;
			position: relative;
			overflow: visible;

			/* 内阴影和外阴影营造立体感 */
			box-shadow:
				inset 0 0 40rpx #444444,
				0 0 20rpx rgba(0, 0, 0, 0.9);

			.stator {
				/* 定子铁芯部分，两个分别靠左和靠右 */
				width: 70rpx;
				height: 70rpx;
				background: linear-gradient(135deg, #3a3f44, #1f2225);
				border-radius: 15rpx / 40rpx;
				/* 椭圆形 */
				position: absolute;
				top: 50%;
				/* 垂直居中 */
				transform: translateY(-50%);
				box-shadow: 0 0 10rpx #222;
				filter: drop-shadow(1rpx 1rpx 1rpx rgba(0, 0, 0, 0.8));

				&.left-stator {
					/* 左侧定子，用clip-path做不规则形状 */
					left: 5rpx;
					clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
					transform-origin: center center;
				}

				&.right-stator {
					/* 右侧定子，左右对称 */
					right: 5rpx;
					clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
					transform: translateY(-50%) scaleX(-1);
					/* 水平翻转 */
					transform-origin: center center;
				}
			}

			.brush {
				/* 电刷部分，两个分别靠左和靠右 */
				width: 16rpx;
				height: 50rpx;
				background: #9e9e9e;
				position: absolute;
				border-radius: 6rpx;
				top: 50%;
				/* 垂直居中 */
				transform: translateY(-50%);
				box-shadow: inset 0 0 6rpx #d7d7d7;
				border: 2rpx solid #666;
				z-index: 12;
				/* 置于转子之上 */

				&.brush-left {
					left: 55rpx;
					box-shadow:
						inset 0 0 6rpx #c5c5c5,
						0 0 6rpx #555;
				}

				&.brush-right {
					right: 55rpx;
					box-shadow:
						inset 0 0 6rpx #c5c5c5,
						0 0 6rpx #555;
				}
			}

			.rotor {
				/* 转子整体，占满外壳 */
				width: 100%;
				height: 100%;
				position: absolute;
				top: 0;
				left: 0;
				transform-origin: center center;
				overflow: visible;

				/* 正转动画 */
				&.spinning {
					animation: spin 1.2s linear infinite;
				}

				/* 反转动画 */
				&.spinning.reverse {
					animation: spin-reverse 1.2s linear infinite;
				}

				.shaft {
					/* 中心轴，椭圆柱体质感 */
					width: 50rpx;
					height: 250rpx;
					background: linear-gradient(180deg, #999999, #444444);
					position: absolute;
					top: 50%;
					left: 50%;
					transform: translate(-50%, -50%);
					border-radius: 15rpx;
					box-shadow: 0 0 12rpx #666 inset;
					z-index: 4;
				}

				.coil {
					/* 线圈部分，两个绕组，用重复条纹表现铜线绕组 */
					width: 30rpx;
					height: 100rpx;
					background: repeating-linear-gradient(45deg,
							#d6a44a,
							#d6a44a 4rpx,
							#b48221 4rpx,
							#b48221 8rpx);
					border-radius: 8rpx;
					position: absolute;
					top: 50%;
					left: 50%;
					transform-origin: center center;
					box-shadow: 0 0 8rpx #bb7f19 inset;
					border: 2rpx solid #8a660d;
					filter: drop-shadow(0 0 2rpx #995f05);
					z-index: 3;

					&.coil-1 {
						transform: translate(-50%, -50%) rotate(50deg);
					}

					&.coil-2 {
						transform: translate(-50%, -50%) rotate(-50deg);
					}
				}

				.commutator {
					/* 换向器，圆形，金属质感 */
					width: 60rpx;
					height: 60rpx;
					background: radial-gradient(circle, #a58f45 0%, #6f5a24 70%);
					border-radius: 50%;
					position: absolute;
					top: 50%;
					left: 50%;
					transform: translate(-50%, -50%);
					box-shadow:
						0 0 15rpx 2rpx #bba44f inset,
						0 0 18rpx #7c6b29;
					border: 3rpx solid #8a7a29;
					z-index: 5;
				}
			}
		}
	}


	/* 🎮 控制按钮区 */
	.buttons {
		display: flex;
		align-items: center;
		justify-content: space-around;
		gap: 40rpx;
		margin-top: 40rpx;
		flex-wrap: wrap;
	}

	.btn {
		background: #2c2c2c;
		/* $button-bg */
		color: #f0f0f0;
		/* $color-text */
		border-radius: 20rpx;
		border: 4rpx solid transparent;
		padding: 40rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		transition: all 0.3s;
		font-size: 60rpx;

		.icon {
			font-size: 50rpx;
			margin-bottom: 10rpx;
		}

		.labeltext {
			display: flex;
			flex-direction: column;
			align-items: center;
		}
	}

	/* ✅ 激活按钮状态（运行中） */
	.btn.forward:not(.disabled) {
		border-color: #3dff67;
		/* $color-forward */
		background: rgba(40, 167, 69, 0.15);
		color: #3dff67;
	}

	.btn.reverse:not(.disabled) {
		border-color: #fff703;
		/* $color-reverse */
		background: rgba(255, 204, 0, 0.15);
		color: #fff703;
	}

	.btn.pause:not(.disabled) {
		border-color: #ff5640;
		/* $color-pause */
		background: rgba(192, 57, 43, 0.15);
		color: #ff5640;
	}

	/* ❌ 禁用状态按钮 */
	.btn.disabled {
		background: #717171;
		/* $button-disabled-bg */
		color: #bdbdbd;
		/* $button-disabled-text */
		border-color: #333333;
		opacity: 0.6;
	}

	/* 🌀 悬浮状态（仅 Web 起效） */
	.btn:hover:not(.disabled) {
		background: #3c3c3c;
		/* $button-hover */
		color: #f0f0f0;
		/* $color-text */
	}

	/* 旋转动画：正向 */
	@keyframes spin {
		0% {
			transform: rotate(0deg);
		}

		100% {
			transform: rotate(360deg);
		}
	}

	/* 旋转动画：反向 */
	@keyframes spin-reverse {
		0% {
			transform: rotate(0deg);
		}

		100% {
			transform: rotate(-360deg);
		}
	}

	/* 呼吸动画 */
	@keyframes breathe {

		0%,
		100% {
			opacity: 0.3;
			box-shadow: 0 0 6rpx rgba(255, 255, 255, 0);
		}

		50% {
			opacity: 1;
			box-shadow: 0 0 14rpx rgba(255, 255, 255, 0.7);
		}
	}
</style>

<style>
	page {
		background-color: #121212;
	}

	@font-face {
		font-family: 'qingyuan';
		src: url('@/static/fonts/qingyuan.ttf');
	}
</style>